//import { Modal } from '@ant-design/react-native';
import { createStore } from '@/airstore';
import MD5 from 'crypto-js/md5';
import CryptoEncUtf8 from 'crypto-js/enc-utf8';
import AES from 'crypto-js/aes';
import ZeroPadding from 'crypto-js/pad-zeropadding';
import {
  setLoginCredentials,
  getLoginCredentials,
  resetLoginCredentials,
} from '../services/accessKeychain';
import axios from 'axios';
import qs from 'qs';
import CookieManager from '@react-native-community/cookies';
import RNCheerio from 'react-native-cheerio';
import ApiClient from '../services/apiClient';
import { saveValue, getValue } from '../services/asyncStorage';
import { APP_STATE, clientId, clientSecret } from '../constants';

export default createStore({
  namespace: 'LoginStore',

  firstLogin: false,
  credentials: {
    username: '',
    password: '',
  },

  tokenRefreshTime: {
    access_token: '',
    refresh_token: '',
    expire_time: 0,
  },
  mrsauthState: {
    action: 'unknown', // send verify relogin / login retry
    retryErrReason: '',
    viewState: '',
    viewGenerator: '',
    viewEvValidation: '',
  },
  authState: APP_STATE.UNKNOWN,

  setAuthState(authState, isFirstLogin) {
    this.authState = authState;
    this.firstLogin = !!isFirstLogin;
  },
  setCredentials(credentials) {
    Object.assign(this.credentials, credentials);
  },
  initRefreshTokenInfo(authToken) {
    if (authToken) {
      ['access_token', 'refresh_token', 'expire_time'].forEach((key) => {
        if (authToken[key] !== undefined) {
          this.tokenRefreshTime[key] = authToken[key];
        }
      });
    }
  },
  async saveToken(tokenResult) {
    let expireTimeout = tokenResult.expires_in;
    if (expireTimeout) {
      expireTimeout = (expireTimeout - 600) * 1000 + Date.now();
    }
    const authToken = {
      access_token: tokenResult.access_token,
      refresh_token: tokenResult.refresh_token,
      expire_time: expireTimeout,
    };
    await saveValue('auth_token', authToken);
    this.initRefreshTokenInfo(authToken);
  },
  encryptPassword(username, password) {
    const ivkey = CryptoEncUtf8.parse(
      MD5(username).toString().substring(8, 24),
    );
    return AES.encrypt(password, ivkey, {
      iv: ivkey,
      padding: ZeroPadding,
    }).toString();
  },

  async checkLogin() {
    const authToken = await getValue('auth_token');
    const isGjInner = await this.checkInnerLoongair(authToken);
    const credentials = await getLoginCredentials();

    console.log('authtoken', authToken, 'credentials', credentials);
    if (authToken) {
      if (
        this.mrsauthState.action === 'send' ||
        this.mrsauthState.action === 'retry'
      ) {
        this.setAuthState(APP_STATE.PUBLIC);
      } else if (authToken.expire_time > Date.now()) {
        // access_token 未过期,继续使用
        this.setAuthState(APP_STATE.PRIVATE);
        this.initRefreshTokenInfo(authToken);
      } else if (isGjInner && credentials) {
        // access_token 过期,尝试用账号登录
        // 成功则更新access_token
        const tokenRes = await this.doTokenAuth(
          credentials.username,
          credentials.password,
        );
        if (tokenRes.errorCode) {
          // 失败进登录页清空auth_token等数据
          await resetLoginCredentials(); // set empty null will fail
          this.setAuthState(APP_STATE.PUBLIC);
        } else {
          this.setAuthState(APP_STATE.PRIVATE);
          this.setCredentials(credentials);
        }
      } else {
        if (isGjInner) {
          //this.setMrsAuth(null, 'login');
        } else {
          this.setMrsAuth(null, 'send');
        }
        this.setAuthState(APP_STATE.PUBLIC);
      }
    } else {
      if (!isGjInner || !credentials) {
        // 外网无authToken, 或者内网无authToken和credential时首次打开
        await this.saveToken({
          access_token: '',
          refresh_token: '',
          expires_in: 0,
        });
        this.setAuthState(APP_STATE.PUBLIC, true);
      } else {
        // 内网有credential登录页面
        //this.setMrsAuth(null, 'login');
        this.setAuthState(APP_STATE.PUBLIC);
      }
    }
  },

  async doTokenAuth(username, passsword) {
    const encPwd = this.encryptPassword(username, passsword);
    const tokenRes = await ApiClient.get('auth/oauth/token', {
      params: {
        grant_type: 'password',
        password: encPwd,
        scope: 'server',
        username: username,
      },
      auth: {
        username: clientId,
        password: clientSecret,
      },
      //headers: {
      //  Authorization: `Basic ${clientBasicAuth}`,
      //},
    });
    if (!tokenRes.errorCode) {
      await this.saveToken(tokenRes.data);
    } else {
      await this.saveToken({
        access_token: '',
        refresh_token: '',
        expires_in: 0,
      });
    }
    return tokenRes;
  },
  async loginUser() {
    if (!this.credentials.username || !this.credentials.password) {
      return;
    }

    try {
      const tokenRes = await this.doTokenAuth(
        this.credentials.username,
        this.credentials.password,
      );
      // maybe need check res text is html, if true set to relogin
      if (tokenRes.errorCode) {
        return tokenRes.errorMsg;
      }
      const credRes = await setLoginCredentials(
        this.credentials.username,
        this.credentials.password,
      );

      if (!credRes.status) {
        console.warn(credRes.error);
      } else {
        this.setAuthState(APP_STATE.PRIVATE);
      }
    } catch (e) {
      console.log(e);
      return e.message;
    }
  },

  async refreshToken() {
    if (!this.tokenRefreshTime.refresh_token) {
      return;
    }
    const tokenRes = await ApiClient.get('auth/oauth/token', {
      params: {
        grant_type: 'refresh_token',
        scope: 'server',
        refresh_token: this.tokenRefreshTime.refresh_token,
      },
      auth: {
        username: clientId,
        password: clientSecret,
      },
      //headers: {
      //  Authorization: `Basic ${clientBasicAuth}`,
      //},
    });
    if (tokenRes.errorCode) {
      this.initRefreshTokenInfo({ expire_time: Date.now() + 10 * 1000 });
      return;
    }
    await this.saveToken(tokenRes.data);
  },
  async logoutUser() {
    const reset = await resetLoginCredentials();

    if (reset) {
      this.setCredentials({ password: '' });
      await this.saveToken({
        access_token: '',
        refresh_token: '',
        expires_in: 0,
      });
      this.setAuthState(APP_STATE.PUBLIC);
      await CookieManager.clearAll();
      await saveValue('gjcookie', null);
      this.setMrsAuth(null, 'relogin');
    }
  },
  setMrsAuth(cheerio, action, retryErr) {
    let { viewEvValidation, viewState, viewGenerator } = this.mrsauthState;
    if (cheerio) {
      try {
        viewEvValidation = cheerio('#form1 #__EVENTVALIDATION').attr('value');
        if (viewEvValidation !== this.mrsauthState.viewEvValidation) {
          viewState = cheerio('#form1 #__VIEWSTATE').attr('value');
          viewGenerator = cheerio('#form1 #__VIEWSTATEGENERATOR').attr('value');
        }
      } catch (err) {
        throw err;
      }
    }
    this.mrsauthState = {
      action,
      retryErrReason: retryErr || '',
      viewState,
      viewGenerator,
      viewEvValidation,
    };
  },
  async checkInnerLoongair(authToken, fromLoginPage) {
    const cookies = await CookieManager.get('https://loongair.cn');
    console.log('cookie manager ', cookies);
    const existMrsauthCookie =
      cookies &&
      Object.keys(cookies).filter((ck) => ck === 'GJVerify' || ck === 'GJd')
        .length > 0;
    try {
      if (existMrsauthCookie) {
        if (!authToken) {
          authToken = await getValue('auth_token');
        }
        const gjAsCookie = await getValue('gjcookie');
        if (
          (gjAsCookie && gjAsCookie.expire_timestamp < Date.now()) ||
          (authToken && authToken.expire_time < Date.now())
        ) {
          /* authToken失效 gjcookie也清空 可以防止外网切换内网 有cookie authToken没有时可能请求验证码错误问题 */
          await CookieManager.clearAll();
          await saveValue('gjcookie', null);
          //} else {  外网下有cookie也需要走验证码登录
          //  this.setMrsAuth(null, 'login');
          //  return true;
        }
      }
      const resp = await axios.get(
        'https://nmrsmobile.loongair.cn/webapi/auth/oauth/token',
        {
          timeout: 25000,
          maxRedirects: 0,
          validateStatus: function (status) {
            return status >= 200 && status < 300;
          },
        },
      );
      const resData = resp.data;
      //const resp = await fetch(
      //  'https://nmrsmobile.loongair.cn/webapi/auth/oauth/token',
      //);
      //const resData = await resp.text();
      /*
      await fetch('https://mrsauth.loongair.cn');
      const mresp = await axios.get('https://mrsauth.loongair.cn');
      console.log(
        'get mrsauth cookie',
        mresp.headers,
        mresp.headers['Set-Cookie'],
      );
      cookies = await CookieManager.get('https://mrsauth.loongair.cn');
      console.log('cookie manager after get', cookies);
      */
      if (
        typeof resData === 'string' &&
        resData.slice(0, 40).toUpperCase().indexOf('<!DOCTYPE HTML>') !== -1
      ) {
        const cheerio = RNCheerio.load(resData);
        this.setMrsAuth(cheerio, 'send');
      } else {
        //Modal.alert(
        //  '验证网络失败',
        //  `接口未正常返回: ${JSON.stringify(resData).slice(0, 100)}`,
        //);
        this.setMrsAuth(
          null,
          'retry',
          `外网验证页面未返回正确结果: ${JSON.stringify(resData).slice(0, 50)}`,
        );
      }
    } catch (err) {
      console.log(
        'nmrsmobile webapi auth direct visit',
        (err.response && err.response.status) || err,
      );
      if (err.response && err.response.status >= 400) {
        if (!existMrsauthCookie) {
          /* 有mrsauth cookie表示前面处于外网中 不进用户密码登录页面 */
          this.setMrsAuth(null, 'login');
          return true;
        } else if (fromLoginPage) {
          // Login index.jsx过来时更新状态
          this.setMrsAuth(null, 'send');
        }
      } else {
        let alertMsg = '';
        if (err.response) {
          if (err.response.status) {
            alertMsg = `${err.response.status}`;
          }
          if (err.response.data && err.response.data.message) {
            alertMsg = `${alertMsg} ${err.response.data.message}`;
          }
        }
        if (err.message) {
          alertMsg = `${alertMsg} ${err.message}`;
        }
        //Modal.alert('验证网络失败', alertMsg);
        this.setMrsAuth(null, 'retry', `验证错误: ${alertMsg}`);
      }
    }
    return false;
  },
  async resetMrsAuthViewState() {
    await CookieManager.clearAll();
    const resp = await axios.get('https://mrsauth.loongair.cn', {
      timeout: 25000,
      maxRedirects: 0,
      validateStatus: function (status) {
        return status >= 200 && status < 300;
      },
    });
    const resData = resp.data;
    if (
      typeof resData === 'string' &&
      resData.slice(0, 40).toUpperCase().indexOf('<!DOCTYPE HTML>') !== -1
    ) {
      const cheerio = RNCheerio.load(resData);
      this.setMrsAuth(cheerio, 'send');
    }
  },
  async requestMrsAuth(mrsFormObj) {
    try {
      const mrsRes = await axios.post(
        'https://mrsauth.loongair.cn',
        qs.stringify({
          __VIEWSTATE: this.mrsauthState.viewState,
          __VIEWSTATEGENERATOR: this.mrsauthState.viewGenerator,
          __EVENTVALIDATION: this.mrsauthState.viewEvValidation,
          //uri: 'https://mrsauth.loongair.cn/',
          //txturls: 'https://mrsauth.loongair.cn/',
          ...mrsFormObj,
        }),
        {
          headers: {
            'content-type': 'application/x-www-form-urlencoded',
            //Cookie: `ASP.NET_SessionId=${cookies['ASP.NET_SessionId'].value}`,
            //Host: 'mrsauth.loongair.cn',
            //Origin: 'https://mrsauth.loongair.cn',
            //Referer: 'https://mrsauth.loongair.cn/',
          },
          //withCredentials: true,
        },
      );
      //console.log(mrsRes.config);
      const html = mrsRes.data;
      //const mrsRes = await fetch('https://mrsauth.loongair.cn', {
      //  method: 'POST',
      //  headers: {
      //    'content-type': 'application/x-www-form-urlencoded',
      //    //Accept:
      //    //  'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*',
      //  },
      //  credentials: 'same-origin',
      //  //credentials: 'include',
      //  body: qs.stringify({
      //    __VIEWSTATE: this.mrsauthState.viewState,
      //    __VIEWSTATEGENERATOR: this.mrsauthState.viewGenerator,
      //    __EVENTVALIDATION: this.mrsauthState.viewEvValidation,
      //    //uri: 'https://mrsauth.loongair.cn/',
      //    //txturls: 'https://mrsauth.loongair.cn/',
      //    ...mrsFormObj,
      //  }),
      //});
      //const html = await mrsRes.text();
      const cheerio = RNCheerio.load(html);
      //console.log(cheerio('#form1').html());
      const alertScript = cheerio('#form1 script');
      if (alertScript) {
        const alertError = alertScript.html().trim();
        if (alertError.indexOf('alert') === 0) {
          return {
            errorMsg: alertError.replace("alert('", '').replace("')", ''),
          };
        }
      }
      if (mrsFormObj.btn_submit$Button1) {
        const btnSubmit2 = cheerio('#form1 #btn_Submit2_Button1').attr('value');
        //if (btnSubmit2 === '验证' || btnSubmit2 === 'Validate') {
        this.setMrsAuth(cheerio, 'verify');
        //}
      } else if (mrsFormObj.btn_Submit3$Button1) {
        this.setMrsAuth(cheerio, 'verify');
      }
      return { errorMsg: '' };
    } catch (err) {
      console.log(err && err.response);
      return { errorMsg: err.message };
    }
  },
  async sendVerifyCode(mrsForm) {
    const authRes = await this.requestMrsAuth({
      txtsendcode: mrsForm.sendto || '',
      ddlSelectPlatform: Number(mrsForm.sendType),
      hidSendType: Number(mrsForm.sendType),
      btn_submit$Button1: '发送验证码',
    });
    if (authRes.errorMsg) {
      await this.resetMrsAuthViewState();
    }
    return authRes.errorMsg;
  },
  async verifyAuthCode(mrsForm) {
    const authRes = await this.requestMrsAuth({
      txtcode: mrsForm.code,
      btn_Submit2$Button1: '验证',
    });
    if (!authRes.errorMsg) {
      let authTokenFailMsg = '';
      try {
        // 获取本地存储的loongair.cn域名cookies
        const cookies = await CookieManager.get('https://loongair.cn');
        const res = await ApiClient.get('auth/gjopenid/token', {
          params: {
            OpenId:
              /*(cookies.openid && cookies.openid.value) || */ mrsForm.sendto,
            GJVerify: cookies.GJVerify.value,
            GJd: cookies.GJd.value,
          },
          auth: {
            username: clientId,
            password: clientSecret,
          },
          withCredentials: true,
        });
        //console.log('gjopenid success', res);
        await saveValue('gjcookie', {
          expire_timestamp: Date.now() + 5 * 60 * 60 * 1000, // 5小时内保留coookie, 重启时认为cookie有效
        });
        await saveValue('gjverify', {
          send_type: mrsForm.sendType,
          sendto: mrsForm.sendto,
        });
        if (!res.errorCode) {
          await this.saveToken(res.data);
          this.setAuthState(APP_STATE.PRIVATE);
        } else {
          authTokenFailMsg = res.errorMsg;
        }
      } catch (err) {
        authTokenFailMsg = err.message;
      }
      if (authTokenFailMsg) {
        await this.saveToken({
          access_token: '',
          refresh_token: '',
          expires_in: 0,
        });
        await this.resetMrsAuthViewState();
        return {
          title: '自动登录失败请重新验证',
          msg: authTokenFailMsg,
        };
      } else {
        return null;
      }
    }
    return {
      title: '验证失败',
      msg: authRes.errorMsg,
    };
  },
  async resendVerifyCode(mrsForm) {
    // cookie未清空直接再次请求mrsauth最多只能发5次
    await CookieManager.clearAll();
    const authRes = await this.requestMrsAuth({
      txtcode: '',
      btn_Submit3$Button1: '其他验证方式',
    });
    if (!authRes.errorMsg) {
      const sendResMsg = await this.sendVerifyCode(mrsForm);
      return sendResMsg;
    }
    return authRes.errorMsg;
  },
});
